import path from "path";
import * as fs from 'fs';
import { BuildHook, IBuildResult, ITaskOptions } from '../@types';
import { PACKAGE_NAME } from "./global";

const settingsFileReg = /^settings\.(\w+\.)?json$/g;
const jsRegisterReg = /^\s*System.register\(\s*[\"\'](.*?)[\"\']\s*,\s*\[\s*(.*?)\]\s*,/;
const jsDependReg = /^\.\/(.*?)\s*$/;

function findSettingFile(srcPath: string): string {
    const files = fs.readdirSync(srcPath);
    for (const file of files) {
        if (settingsFileReg.test(file))
            return path.join(srcPath, file);
    }

    throw new Error("Cannot find settings.json in dir:" + srcPath);
}

function findSystemJsFile(dstPat: string): string {
    const lines = fs.readFileSync(path.join(dstPat, 'index.html'), 'utf-8').split(/\r?\n/);
    for (const line of lines) {
        const match = line.match(/<script src="(.*?system.*?\.js)".*?>/);
        if (match) {
            return match[1];
        }
    }
}

function collectMapInJSFile(dstPath: string, jsFile: string, outImports: { [key: string]: string }, outChunks: { [key: string]: string }) {
    const lines = fs.readFileSync(path.join(dstPath, jsFile), 'utf-8').split(/\r?\n/);
    for (const line of lines) {
        const match = line.match(jsRegisterReg);
        if (!match) continue;
        const chunkName = match[1];
        outImports[chunkName] = jsFile;

        const imports = match[2];
        for (const str of imports.split(',')) {
            const dep = eval(str);
            if (!dep || dep in outChunks) continue;
            if (dep === "cc") {
                outChunks[dep] = "./fake_cc.js";
                continue;
            }
            const depm = dep.match(jsDependReg);
            if (!depm) {
                throw new Error(`Cannot parse js depend: ${str} in ${jsFile}`);
            }
            outChunks[dep] = `chunks:///_virtual/${depm[1]}`
        }
    }
}

function generateWorkerSpaceMap(dstPath:string, scriptMoved: boolean): string {
    const file = findSettingFile(path.join(dstPath, 'src'));
    const settings = JSON.parse(fs.readFileSync(file, 'utf-8'));
    const allBundles = settings.assets.projectBundles;
    const remoteBundles = settings.assets.remoteBundles;
    const bundleVers = settings.assets.bundleVers;
    const subpackages = settings.assets.subpackages;
    const md5Bundles = Object.keys(bundleVers);
    let jsImports: {[key:string]: string} = {};
    let jsChunks: {[key:string]: string} = {};
    for (const name of allBundles) {
        const bundleVersion = md5Bundles.indexOf(name) !== -1 ? bundleVers[name]: undefined;
        const isRemote = remoteBundles.indexOf(name) !== -1;
        const isSubpackage = subpackages.indexOf(name) !== -1;
        const jsFile = path.join(
            isSubpackage ? 'subpackages' : (isRemote ? (scriptMoved ? 'src/bundle-scripts' : 'remote') : 'assets')
            , name
            , isSubpackage ? 'game.js' : (bundleVersion ? `index.${bundleVersion}.js` : 'index.js')
        );
        collectMapInJSFile(dstPath, jsFile, jsImports, jsChunks);
    }

    const chunksDir = path.join(dstPath, 'src', 'chunks');
    fs.readdirSync(chunksDir).forEach(file=>{
        collectMapInJSFile(dstPath, path.join('src', 'chunks', file), jsImports, jsChunks);
    });

    return JSON.stringify({
        systemJs: findSystemJsFile(dstPath),
        imports: jsImports,
        chunks: jsChunks,
    });
}

export const throwError = true;

export const onAfterBuild: BuildHook.onAfterBuild = async function(options: ITaskOptions, result: IBuildResult) {
    const root = Editor.Project.path;
    const dir = path.join(root, 'extensions', PACKAGE_NAME, 'scripts');
    const target = result.dest;
    fs.copyFileSync(path.join(dir, 'fake_cc.js'), path.join(target, 'fake_cc.js'));
    fs.copyFileSync(path.join(dir, 'worker.js'), path.join(target, 'worker.js'));
    fs.copyFileSync(path.join(dir, 'systeminit_bundle.js'), path.join(target, 'systeminit.js'));
    const json = generateWorkerSpaceMap(result.dest, options.moveRemoteBundleScript || options.platform == 'wechatgame');
    fs.writeFileSync(path.join(target, 'workerspace_map.json'), json);
};

